package com.its.common.net.core.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

/**
 * @Author xiaxp
 * @Date 9/2/22 14:08
 * @Description
 */
public class CustomHeadTailDecoder extends ByteToMessageDecoder {
    private ByteBuf head;
    private ByteBuf tail;

    public CustomHeadTailDecoder(byte[] headDelimiter, byte[] tailDelimiter) {
        head = Unpooled.wrappedBuffer(headDelimiter);
        tail = Unpooled.wrappedBuffer(tailDelimiter);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int headLength = head.readableBytes();
        int tailLength = tail.readableBytes();

        //给读指针打个标记，重置读指针的时候重置到此位置
        in.markReaderIndex();
        if (in.readableBytes()< headLength + tailLength + 1) {
            return;
        }

        // 开始标识下标
        int beginIdx = indexOf(in, head);
        // 结束标识下标
        int endIdx = indexOf(in, tail);

        // 如果缓存区找不到开始标识，跳过该段字节
        if (beginIdx == -1) {
            in.readerIndex(in.writerIndex());
            return;
        }

        // 如果缓冲区找不到结束下标，或者下标小于开始标识，则从开始标识开始读取
        if (endIdx == -1 || endIdx < beginIdx) {
            in.readerIndex(beginIdx);
            return;
        }

        // 将标识之间的数据提取出来，给后面的解码器使用
        ByteBuf frame = in.retainedSlice(beginIdx, endIdx - beginIdx + tailLength);
        out.add(frame);
        // 更新读取下标
        in.skipBytes(endIdx + tailLength);
    }

    private static int indexOf(ByteBuf haystack, ByteBuf needle) {
        for (int i = haystack.readerIndex(); i < haystack.writerIndex(); i++) {
            int haystackIndex = i;
            int needleIndex;
            for (needleIndex = 0; needleIndex < needle.capacity(); needleIndex++) {
                if (haystack.getByte(haystackIndex) != needle.getByte(needleIndex)) {
                    break;
                }
                haystackIndex++;
                if (haystackIndex == haystack.writerIndex() && needleIndex != needle.capacity() - 1) {
                    return -1;
                }
            }
            if (needleIndex == needle.capacity()) {
                return i - haystack.readerIndex();
            }
        }
        return -1;
    }

    private static byte[] extractByteBuf(Object obj) {
        ByteBuf in = (ByteBuf)obj;
        int readableBytes = in.readableBytes();
        byte[] bytes =new byte[readableBytes];
        in.readBytes(bytes);
        return bytes;
    }
}
